package com.xiaoyu.web.sentinel;

import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.nacos.api.config.ConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.SmartLifecycle;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @Author：小鱼
 * @data: 2023/6/30 14:41
 */
@Slf4j
public class RegistryNacosDatasourceHandler implements SmartLifecycle {

    private DefaultListableBeanFactory beanFactory;

    private NacosDataSource<List<FlowRule>> bean;

    public RegistryNacosDatasourceHandler(DefaultListableBeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    /**
     * 通过反射获取NacosDataSource当中指定字段的值
     */
    private <T> T getFieldValue(String fieldName) throws IllegalAccessException {
        Field field = ReflectionUtils.findField(NacosDataSource.class, fieldName);
        field.setAccessible(true);
        return (T) field.get(this.bean);
    }

    @Override
    public void start() {
        log.info("容器启动...");
        this.bean = beanFactory.getBean(NacosDataSource.class);
        try {
            //通过反射,获取ConfigService,用来推送流控规则
            ConfigService service = getFieldValue("configService");
            //流控文件
            String dataId = getFieldValue("dataId");
            //组名
            String groupId = getFieldValue("groupId");
            /**
             * 将自定义的Nacos流控规则数据源注册到sentinel框架当中,
             * 以便sentinel框架在收到控制台配置的规则推送后,调用流控规则
             * 持久化逻辑，即调类：NacosFlowRuleWritableDataSource
             */
            WritableDataSource dataSource =
                    new NacosFlowRuleWritableDataSource(service,dataId,groupId);
            WritableDataSourceRegistry.registerFlowDataSource(dataSource);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void stop() {

    }

    @Override
    public boolean isRunning() {
        return true;
    }

    @Override
    public boolean isAutoStartup() {
        return true;
    }
}
